package com.migrate.module.task;

import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.migrate.module.config.ScrollDataSourceConfig;
import com.migrate.module.constants.Constants;
import com.migrate.module.domain.EtlStatistical;
import com.migrate.module.mapper.migrate.MigrateScrollMapper;
import com.migrate.module.service.MigrateConfigService;
import com.migrate.module.util.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSession;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.sql.*;
import java.util.Date;
import java.util.List;

/**
 * 处理关于 表的数据量统计缓存，避免获取同步进度的计算效率过低
 * 统计每天的订单表和订单详情表产生的数据量，用来快速的计算出迁移进度
 *
 * @author zhonghuashishan
 */
@Component
@Slf4j
public class CountCacheTask {

    @Resource
    private ScrollDataSourceConfig scrollDataSourceConfig;

    @Resource
    private MigrateScrollMapper migrateScrollMapper;

    @Resource
    private MigrateConfigService migrateConfigService;

//    @PostConstruct
    public void init(){
        countRefresh();
    }

    /**
     * 每小时执行一次同步
     */
    @Scheduled(cron = "0 0 0/1 * * ?")
    void countRefresh(){
       try {
           Constants.statisticalCountMap.clear();
           List<String> domainNameList = migrateConfigService.getDomainNames();
           for (String domain:domainNameList){
               // 获取该业务系统下的表名称
               List<String> tableList = migrateConfigService.getTablesToDomain(domain);
               // 获取所有配置的需要同步的表
               for (String tableName:tableList){
                   log.info("开始同步："+tableName+"的表数据");
                   EtlStatistical etlStatistical = new EtlStatistical();
                   etlStatistical.setLogicModel(tableName);
                   etlStatistical.setDomain(domain);

                   EtlStatistical etlStatistical1 = migrateScrollMapper.getMaxDateEtlStatistical(etlStatistical);
                   // 验证单个表的数据明细是否已统计，如果未统计则默认从最小时间天数 开始统计，否则只更新最近2天的数据(防止跨天数据产生)
                   if (ObjectUtils.isNotEmpty(etlStatistical1)){
                       //已统计的最大时间格式
                       Integer statisticalTime = etlStatistical1.getStatisticalTime();
                       Long distanceDays = DateUtils.getDistanceDays(String.valueOf(statisticalTime), DateUtils.format(new Date()) + "");
                       Date minDate = null;
                       if (distanceDays < 2){
                           // 更新最近15天的该表统计数量
                           minDate = DateUtils.addDays( -2);
                       } else {
                           minDate = DateUtils.parseStrToDate(String.valueOf(statisticalTime), DateUtils.DATE_FORMAT_YYYYMMDD);
                       }
                       saveStatistical(minDate,domain,tableName,false);
                   } else {
                       // 先取最小的日期，然后以该日期，以天为单位开始统计
                       Date minDate = getMinDate(domain,tableName);
                       saveStatistical(minDate,domain,tableName,true);
                   }
               }
           }

       }catch (Exception e){
            e.printStackTrace();
       }
    }

    /**
     * 按天去计算出每天该表的实际数据量
     * @param minDate 开始计算的时间
     */
    private void saveStatistical(Date minDate,String domain,String tableName,boolean isNew){
       try {
           int num = DateUtils.daysBetween(minDate, new Date());

            for (int i=0;i<num;i++){
                Date startDate = DateUtils.getStartTimeOfDate(DateUtils.addDays(minDate, i));
                Date endDate =  DateUtils.getEndTimeOfDate(DateUtils.addDays(minDate, i));
                log.info("开始统计：startDate=" + DateUtils.parseDateToStr(startDate, "yyyyMMdd") + ",endDate=" + DateUtils.parseDateToStr(endDate, "yyyyMMdd"));
                Integer statisticalCount = countStatistical(tableName,domain,startDate,endDate);
                this.saveOrUpdateStatistical(tableName,domain, startDate, statisticalCount, isNew);
            }
       }catch (Exception e){
           e.printStackTrace();
       }
    }

    /**
     * 统计每个表的单日数据
     * @return
     */
    private Integer countStatistical(String tableName,String domain, Date startDate,  Date endDate){
        SqlSession session = null;
        PreparedStatement pst = null;
        try {

            String sql = " select count(*) from "+tableName+" where create_time >= ? and create_time <= ?";
            session = scrollDataSourceConfig.getSqlSession(domain, 1);
            pst = session.getConnection().prepareStatement(sql);
            pst.setTimestamp(1,new Timestamp(startDate.getTime()));
            pst.setTimestamp(2,new Timestamp(endDate.getTime()));

            ResultSet resultSet = pst.executeQuery();
            while (resultSet.next()){
                return resultSet.getInt(1);
            }
            return 0;
        }catch (Exception e){
            return 0;
        } finally {
            closeSqlSession(session, pst, domain, 1);
        }

    }
    /**
     * 新增或者保存
     * @param logicModel
     * @param statisticalTime
     */
    private void saveOrUpdateStatistical(String logicModel,String domain, Date statisticalTime, Integer statisticalCount,boolean isNew){
        EtlStatistical statistical = new EtlStatistical();
        statistical.setLogicModel(logicModel);
        statistical.setDomain(domain);
        statistical.setStatisticalTime(DateUtils.format(statisticalTime));
        statistical.setStatisticalCount(statisticalCount);
        if (isNew){
            statistical.setCreateTime(new DateTime());
            statistical.setUpdateTime(new DateTime());
            migrateScrollMapper.insertEtlStatistical(statistical);
        } else {
            EtlStatistical etlStatistical = migrateScrollMapper.getEtlStatistical(statistical);
            if (etlStatistical == null){
                statistical.setCreateTime(new DateTime());
                statistical.setUpdateTime(new DateTime());
                migrateScrollMapper.insertEtlStatistical(statistical);
            } else {
                etlStatistical.setUpdateTime(new DateTime());
                migrateScrollMapper.updateEtlStatistical(statistical);
            }
        }
    }

    /**
     *  获取当前表的默认最小更新时间的日期
     * @param tableName
     * @return
     */
    private Date getMinDate(String domain,String tableName){
        SqlSession session = null;
        PreparedStatement pst = null;
        try {
            String sql = "select create_time from "+tableName+" order by create_time limit 1";
            session = scrollDataSourceConfig.getSqlSession(domain, 1);
            pst = session.getConnection().prepareStatement(sql);

            ResultSet resultSet = pst.executeQuery();
            while(resultSet.next()){
                return resultSet.getDate(1);
            }
            return null;
        }catch (Exception e){
            e.printStackTrace();
        }finally {
             closeSqlSession(session, pst, domain, 1);
        }
        return null;
    }
    /**
     * 关闭连接
     * @param session
     * @param pst
     * @param domain
     * @param dataSourceType
     */
    private void closeSqlSession(SqlSession session, PreparedStatement pst, String domain, Integer dataSourceType){
        if(pst!=null){
            try {
                pst.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        scrollDataSourceConfig.closeSqlSession(session,domain, dataSourceType);
    }
}
